﻿Option Explicit On

Imports System.Xml
Imports System.IO
Imports System.Security.Permissions
Imports System.Security.Cryptography
Imports System.Security.Cryptography.X509Certificates
Imports System.Security.Cryptography.Xml

Public Class frmFerramentasAssinaturaArquivo
    Private Sub frmFerramentasAssinatura_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        Call CloseFindReplace(Me)
    End Sub
    Private Sub tbPadrao_ItemClicked(ByVal sender As System.Object, ByVal e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles tbPadrao.ItemClicked
        Try
            Select Case e.ClickedItem.Tag
                Case "OP"
                    Call AbrirXML()
                Case "IDT"
                    Call XMLIdentacao()
            End Select
        Catch ex As Exception
            Call SendError(ex.Message, ex.StackTrace)
        End Try
    End Sub
    ''' <summary>
    ''' Abre documento XML e valida-o
    ''' </summary>
    ''' <remarks>3.4.3.26</remarks>
    Private Sub AbrirXML(Optional ByVal strFileName As String = "")
        Try
            Dim strValElement As String = ""
            Dim strXML As String = ""
            Dim MyXml As New XmlDocument()
            Dim myFileName As OpenFileDialog = New OpenFileDialog()
            With lblAssinatura
                .Text = "Assinatura não verificada!"
                .BackColor = Color.LemonChiffon
            End With
            If IsEmpty(strFileName) Then
                With myFileName
                    .Title = "Arquivos XML"
                    .Filter = "Arquivos XML (*.xml)|*.xml"
                    .ShowDialog()
                    strFileName = .FileName
                End With
            End If
            If Trim(strFileName) = "" Then Exit Sub
            Me.Text = "Validar Assinatura Digital [" & strFileName & "]"
            With MyXml
                .PreserveWhitespace = False
                .Load(strFileName)
                '-- mostrando conteudo
                txtXML.Text = .OuterXml
                If .FirstChild.Name = "xml" Then
                    strXML = .GetElementsByTagName(.FirstChild.NextSibling.Name.ToString).Item(0).OuterXml
                    .LoadXml(strXML)
                End If
                '-- RETORNOS
                Select Case .FirstChild.Name
                    Case "retEnviNFe"
                        lblDocumento.Text = "Recibo de Envio de Lote"
                        Exit Sub
                    Case "retConsReciNFe "
                        lblDocumento.Text = "Recibo de Processamento de Lote"
                        Exit Sub
                    Case "retCancNFe "
                        lblDocumento.Text = "Retorno da Solicitação de Cancelamento"
                        Exit Sub
                    Case "retInutNFe "
                        lblDocumento.Text = "Retorno da Solicitação de Inutilização"
                    Case "retConsSitNFe"
                        lblDocumento.Text = "Retorno de Consulta de Situação"
                        Exit Sub
                    Case "retConsStatServ"
                        lblDocumento.Text = "Retorno de Consulta do Status do Serviço"
                        Exit Sub
                    Case "retConsCad"
                        lblDocumento.Text = "Retorno de Consulta de Cadastro"
                        Exit Sub
                    Case "nfeProc"
                        lblDocumento.Text = "Protocolo de autorização"
                        strValElement = "NFe"
                    Case "NFe", "infNFe"
                        lblDocumento.Text = "Dados da NFe"
                        strValElement = "NFe"
                    Case "enviNFe"
                        lblDocumento.Text = "Envio de Lote da NFe"
                        strValElement = "NFe"
                    Case "cancNFe"
                        lblDocumento.Text = "Cancelamento de NFe"
                        strValElement = "cancNFe"
                    Case "procCancNFe"
                        lblDocumento.Text = "Protocolo de Cancelamento de NFe"
                        strValElement = "cancNFe"
                    Case "inutNFe"
                        lblDocumento.Text = "Inutilização de Numeração de NFe"
                        strValElement = "inutNFe"
                    Case "procInutNFe"
                        lblDocumento.Text = "Protocolo de Inutilização de Numeração de NFe"
                        strValElement = "inutNFe"
                    Case "conSitNFe", "consSitNFe"
                        lblDocumento.Text = "Consulta de Situação da NFe"
                        Exit Sub
                    Case "consStatServ"
                        lblDocumento.Text = "Consulta de Status do Serviço"
                        Exit Sub
                    Case "consCad"
                        lblDocumento.Text = "Consulta de Cadastro de Contribuintes"
                        Exit Sub
                    Case Else
                        lblDocumento.Text = "Documento desconhecido"
                        Exit Sub
                End Select
            End With
            If ValidarAssinaturaDigNFe(strFileName, strValElement) = True Then
                With lblAssinatura
                    .Text = "Assinatura válida!"
                    .BackColor = Color.LightGreen
                End With
            Else
                With lblAssinatura
                    .Text = "Assinatura inválida!"
                    .BackColor = Color.Bisque
                End With
            End If
        Catch ex As Exception
            Call SendError(ex.Message, ex.StackTrace)
            txtMensagens.Text = ex.Message
        End Try
    End Sub
    ''' <summary>
    ''' Rotina de identação de XML após a validação
    ''' </summary>
    ''' <remarks>3.4.3.26</remarks>
    Private Sub XMLIdentacao()
        Try
            '-- solução 02
            Dim w As New MemoryStream()
            Dim myWriter As New XmlTextWriter(w, Nothing)

            Dim document As New XmlDocument()
            document.LoadXml(txtXML.Text)
            myWriter.Formatting = Formatting.Indented
            document.WriteContentTo(myWriter)

            myWriter.Flush()
            w.Seek(0L, SeekOrigin.Begin)

            Dim reader As New StreamReader(w)

            txtXML.Text = reader.ReadToEnd()
            txtXML.Update()
        Catch ex As Exception
            Call SendError(ex.Message, ex.StackTrace)
        End Try
    End Sub
    ''' <summary>
    ''' Validador de assinatura digital para NFe e afins
    ''' </summary>
    ''' <param name="FilePath">Caminho do arquivo XML</param>
    ''' <param name="strElement">Nome do elemento assinado</param>
    ''' <returns></returns>
    ''' <remarks>Functional</remarks>
    Public Function ValidarAssinaturaDigNFe(ByVal FilePath As String, Optional ByVal strElement As String = "NFe") As Boolean
        Try
            '-- carregar o XML da NF-e
            Dim xml As New XmlDocument()
            xml.PreserveWhitespace = True
            xml.Load(FilePath)

            If xml.GetElementsByTagName(strElement).Count > 0 Then
                Return CheckSignatureNFe(xml.GetElementsByTagName(strElement))
            Else
                Return False
            End If
        Catch ex As Exception
            Call MsgBox(ex.Message, MsgBoxStyle.Critical)
            Return False
        End Try
    End Function
    ''' <summary>
    ''' Verifica se tem assinatura e se está correta
    ''' </summary>
    ''' <param name="tagVal">Tag assinada</param>
    ''' <returns></returns>
    ''' <remarks>3.4.3.26</remarks>
    Private Function CheckSignatureNFe(ByVal tagVal As XmlNodeList) As Boolean
        Try
            '-- pegar a Tag "NFe", à que contem assinatura dig.
            Dim nodeNFe As XmlNodeList = tagVal
            Dim NFe As String = nodeNFe(0).OuterXml.ToString

            '--carregar o XML da NFe 
            Dim xmlNFe As New XmlDocument()
            xmlNFe.PreserveWhitespace = True
            xmlNFe.LoadXml(NFe)

            '--Carregar a assinatura
            Dim signedXml As New SignedXml(xmlNFe)
            Dim nodeList As XmlNodeList = xmlNFe.GetElementsByTagName("Signature")
            signedXml.LoadXml(nodeList(0))

            '--buscar o KeyInfo da assinatura
            Dim keyInfoItems As IEnumerator = signedXml.KeyInfo.GetEnumerator()
            keyInfoItems.MoveNext()
            Dim keyInfoX509 As KeyInfoX509Data = keyInfoItems.Current() '(KeyInfoX509Data)keyInfoItems.Current

            '--buscar o certificado do KeyInfo
            Dim keyInfoCert As X509Certificate2 = keyInfoX509.Certificates(0)

            '--Validar se assinatura é valida
            Return signedXml.CheckSignature(keyInfoCert.PublicKey.Key)
        Catch ex As Exception
            Return False
        End Try
    End Function

    Private Sub txtXML_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles txtXML.DragEnter
        e.Effect = DragDropEffects.Move
    End Sub

    Private Sub txtXML_FileDrop(ByVal sender As Object, ByVal e As ScintillaNet.FileDropEventArgs) Handles txtXML.FileDrop
        Select Case e.FileNames.Length
            Case 0
            Case 1
                Call AbrirXML(e.FileNames(0).ToString)
            Case Else
                If e.FileNames.Length > 10 Then
                    If MsgBox("Estou prestes a abrir " & e.FileNames.Length & " arquivos, posso prosseguir?", MsgBoxStyle.Question + MsgBoxStyle.YesNo) = MsgBoxResult.No Then
                        Exit Select
                    End If
                End If
                Call AbrirXML(e.FileNames(0).ToString)
                For lngFiles As Integer = 1 To e.FileNames.Length - 1
                    Dim frmChild As New frmFerramentasAssinaturaArquivo()
                    With frmChild
                        .MdiParent = MDIMain
                        .Icon = MDIMain.Icon
                        .Show()
                        .AbrirXML(e.FileNames(lngFiles).ToString)
                    End With
                Next
        End Select

    End Sub
End Class